<template>
  <div :class="$style.page" class="flex h-100 o-h">
    <div :class="$style.tools" class="col-flex">
      <div :class="$style.operate">
        <div :class="$style.upload">
          <input type="file" accept="image/png,image/jpeg" @change="onFileChange" />
        </div>

        <el-button-group size="small">
          <el-button type="primary" @click="updateRandom">随机更新</el-button>
          <el-button type="danger" @click="updateJSON">转换 JSON</el-button>
        </el-button-group>

        <div :class="$style.item">
          <span :class="$style.name">复制间隔：</span>
          <el-input-number v-model="pageOpts.copyGap" @keyup.stop @keydown.stop></el-input-number>
        </div>
      </div>

      <div :class="$style.textarea" class="f-x">
        <textarea
          ref="copyRef"
          v-model="pageOpts.json"
          @keyup.stop
          @keydown.stop
          @input="onTextareaInput"
          @paste="onTextareaPaste"
          placeholder="请输入"
        ></textarea>
      </div>
    </div>

    <div :class="$style.wrapper">
      <el-collapse :class="$style['device-info']" accordion>
        <el-collapse-item name="1">
          <template #title>
            <span class="pl-xs">
              <el-input
                size="small"
                v-model="checkedInfo.name"
                placeholder="请输入"
                @click.stop
                @keyup.stop
                @keydown.stop
              />
            </span>
          </template>
          <div class="pl-xs pr-xs">
            <div class="flex">
              <span>类型：</span><span>{{ checkedInfo.type }}</span>
            </div>
            <div class="flex">
              <span>编号：</span>
              <span>
                <el-input
                  size="small"
                  v-model="checkedInfo.deviceCode"
                  placeholder="请输入"
                  @keyup.stop
                />
              </span>
            </div>
            <div class="flex" v-if="checkedInfo.type === DEVICE_TYPE.DOT">
              <span>单位：</span>
              <span>
                <el-input
                  size="small"
                  v-model="checkedInfo.unit"
                  placeholder="请输入"
                  @keyup.stop
                />
              </span>
            </div>
            <div class="flex">
              <span>坐标：</span>
              <span>
                x: {{ checkedInfo.style?.x.toFixed(2) }}, y: {{ checkedInfo.style?.y.toFixed(2) }}
              </span>
            </div>
            <div class="flex">
              <span>角度：</span>
              <el-slider
                class="f-x"
                v-model="checkedInfo.rotate"
                :min="0"
                :max="360"
                show-input
                size="small"
                @keyup.stop
              />
            </div>

            <el-input type="textarea" :value="JSON.stringify(checkedInfo, void 0, 2)"></el-input>
          </div>
        </el-collapse-item>
      </el-collapse>

      <z-drag
        ref="dragRef"
        :bg-src="pageOpts.bgSrc"
        v-model="pageOpts.scale"
        @mousemove="onDragMouseMove"
        @mouseup="onDragMouseUp"
      >
        <div class="e-drag__dot-content">
          <t-plane-device
            :list="pageOpts.list"
            type="devices"
            :active="pageOpts.index"
            :show-name="true"
            @click="onDotClick"
            @mousedown.stop="onDotMouseDown"
            @mouseup.stop="onDragMouseUp"
          ></t-plane-device>
        </div>
      </z-drag>
    </div>
  </div>
</template>

<script lang="ts" setup>
import tPlaneDevice from './components/plane-device/index.vue'
import { DEVICE_TYPE } from '@/api/key'
import { getOpts } from './data'
import type { Item } from './type'

const pageOpts = reactive(getOpts())

const checkedInfo = computed(() => {
  let obj: Partial<import('./type').Item> = {}
  if (pageOpts.index < 0) return obj
  obj = pageOpts.list[pageOpts.index]
  return obj
})

const onDotClick = (_index: number, _item: import('./type').Item) => {
  // console.log( _index, _item )
}

const toggleTarget = (index: number) => {
  if (pageOpts.index == index) return
  pageOpts.index = index
}

const move = {
  x: 0,
  y: 0
}

const onDotMouseDown = (ev: MouseEvent | TouchEvent, index: number) => {
  pageOpts.isMove = true
  toggleTarget(index)

  // 判断鼠标还是触点
  const isMouse = ev instanceof TouchEvent
  if (isMouse) {
    // 获取第一个触点
    const dot = ev.changedTouches[0]
    move.x = dot.clientX
    move.y = dot.clientY
  } else {
    move.x = ev.pageX
    move.y = ev.pageY
  }
}

const dragRef = ref()
const onDragMouseMove = (ev: MouseEvent | TouchEvent) => {
  if (!pageOpts.isMove || pageOpts.index < 0) return
  // 判断鼠标还是触点
  const isMouse = ev instanceof TouchEvent
  let x = 0,
    y = 0
  if (isMouse) {
    // 获取第一个触点
    const dot = ev.changedTouches[0]
    x = dot.clientX
    y = dot.clientY
  } else {
    x = ev.pageX
    y = ev.pageY
  }

  const s = pageOpts.scale

  pageOpts.list[pageOpts.index].mx = (x - move.x) / s
  pageOpts.list[pageOpts.index].my = (y - move.y) / s
}

const onDragMouseUp = () => {
  if (!pageOpts.isMove) return
  pageOpts.isMove = false
  if (pageOpts.index < 0) return
  const dot = pageOpts.list[pageOpts.index]
  let x = dot.mx ?? 0
  let y = dot.my ?? 0
  if (x != 0) {
    x += dot.style.x
    dot.style.x = x
  }
  if (y != 0) {
    y += dot.style.y
    dot.style.y = y
  }

  dot.mx = 0
  dot.my = 0
  addRecord()
}

const onTextareaInput = (e: Event) => {
  // @ts-ignore
  formatJosn(e.target.value)
}

const onTextareaPaste = (e: ClipboardEvent) => {
  console.log('paste', e)
  // // 获取粘贴的内容
  // const clipboardData = e.clipboardData
  // const pastedData = clipboardData.getData('text')
  // formatJosn(pastedData)
}

const formatJosn = (text: string) => {
  try {
    const list = JSON.parse(text)
    pageOpts.list = list.map((item: AnyObject) => {
      const style = item.style || { x: 0, y: 0 }
      // style.x *= 750 / 100
      // style.y *= 652 / 100
      return {
        ...item,
        style,
        rotate: item.rotate || 0,
        value: item.value || 0,
        color: item.color || '',
        status: 0,
        error: 0
      }
    })
  } catch (er) {
    console.log(er)
    if (text.replace(/^\s*|\s*$/g, '').length) {
      ElMessage({
        message: 'JOSN 格式错误！',
        type: 'error',
        plain: true,
        grouping: true
      })
    }
  }
  addRecord()
}

const updateRandom = () => {
  pageOpts.list.forEach(item => {
    if (item.type == 'DOT') {
      item.value = Math.floor(Math.random() * 100)
      return
    }
    item.status = Math.random() > 0.5 ? 1 : 0
    item.error = Math.random() > 0.5 ? 1 : 0
  })
}

const accept = ['png', 'jpg']
const onFileChange = (e: Event) => {
  // @ts-ignore
  const files = e.target.files
  const file = files[0]
  let filename = file.name
  const type = filename.split('.').pop().toLowerCase()
  if (!accept.includes(type)) {
    ElNotification({
      type: 'error',
      title: '文件错误',
      message: `文件格式不正确,转换格式支持${accept.join('、')}！`
    })
  }
  filename = file.name.substring(0, file.name.lastIndexOf('.'))
  console.log(file)
  const render = new FileReader()
  render.onload = e => {
    const base = e.target?.result
    pageOpts.bgSrc = base as string
  }
  render.readAsDataURL(file)
  // @ts-ignore
  e.target.value = ''
}

const updateJSON = () => {
  console.log(toRaw(pageOpts.list))
  const list = pageOpts.list.map(item => {
    const { name, type, style, rotate = 0, color, unit, deviceCode } = item
    return `{
      "name": "${name}",
      "type": "${type}"${
      style.x > 0 || style.y > 0 || rotate > 0
        ? `,
      ${
        style.x > 0 || style.y > 0 ? `"style": { "x": ${style.x ?? 0}, "y": ${style.y ?? 0} }` : ''
      }${
            rotate > 0
              ? `,
      ${rotate > 0 ? `"rotate": ${rotate}` : ''}`
              : ''
          }`
        : ''
    }${
      color
        ? `,
       "color": "${color}"`
        : ''
    }${
      unit
        ? `,
       "unit": "${unit}"`
        : ''
    }${
      deviceCode
        ? `,
       "deviceCode": "${deviceCode}"`
        : ''
    }
    }`
  })
  const text = `[${list.join(',')}]`
  pageOpts.json = text
}

// 复制对象
const copyObject = (obj: any) => {
  let newObj: any = obj
  if (obj instanceof Array) {
    newObj = obj.map(it => copyObject(it))
  } else if (Object.prototype.toString.call(obj) == '[object Object]') {
    newObj = {}
    Object.keys(obj).forEach(key => {
      let val = obj[key]
      if (val instanceof Array || Object.prototype.toString.call(obj) == '[object Object]') {
        val = copyObject(val)
      }
      newObj[key] = val
    })
  }
  return newObj
}

const getCodeNumber = (key: string, code: string = '') => {
  return Number(code.replace(key, ''))
}

const getDevOrDotCode = (type: string, deviceCode = '') => {
  if (type !== DEVICE_TYPE.DOT) return deviceCode
  return deviceCode.split('_')[0]
}

// 获取设备数量
const getDeviceNum = (item: Item, key: string) => {
  const devices = pageOpts.list
  const type = item.type
  let num = 0
  const tDevs = devices
    .filter(it => it.deviceCode && it.deviceCode.indexOf(key) == 0 && type == it.type)
    .sort((p, n) => {
      const pn = getCodeNumber(key, getDevOrDotCode(type, p.deviceCode))
      const nn = getCodeNumber(key, getDevOrDotCode(type, n.deviceCode))
      return pn - nn
    })
  // 查找缺失或追加
  for (let i = 0; i < tDevs.length; i++) {
    const td = tDevs[i]
    const n = getCodeNumber(key, getDevOrDotCode(type, td.deviceCode))
    if (n - num > 1) break
    if (n > 0) num = n
  }
  return num
}

// 设备名称 + 编号
const getDeviceName = (item: Item) => {
  let key = item.deviceCode
  if (item.name.indexOf('#') > -1) {
    item.name = item.name.split('#')[1]
  }
  if (!key) return item.name
  key = getDevOrDotCode(item.type, key)
  key = key.replace(/[^a-zA-Z]/g, '')
  const num = getDeviceNum(item, key)
  return `${num + 1}#${item.name}`
}

// 获取设备编号
const getDeviceCode = (item: Item) => {
  let key = item.deviceCode
  if (!key) return ''
  let after = ''
  if (item.type == DEVICE_TYPE.DOT) {
    const ar = key.split('_')
    key = ar[0]
    after = ar.slice(1).join('_')
  }
  key = key.replace(/[^a-zA-Z]/g, '')
  const num = getDeviceNum(item, key)
  return `${key}${num + 1}${after ? '_' + after : ''}`
}

// 操作记录数据
const operateRecord: {
  max: number
  list: typeof pageOpts[]
  tsp: number
  time: number
} = {
  max: 50,
  list: [],
  tsp: 0,
  time: 500
}

// 添加操作记录
const addRecord = () => {
  const tsp = Date.now()
  // 限制操作速度（如键盘长按移动）
  if (tsp - operateRecord.tsp < operateRecord.time) return
  operateRecord.tsp = tsp

  const list = operateRecord.list
  const len = list.length
  // 长度超过先删除
  if (len >= operateRecord.max) {
    list.splice(0, 1)
  }
  const newObj = copyObject(pageOpts)
  list.push(newObj)
}

// 回退操作数据
const backOperate = () => {
  const list = operateRecord.list
  const len = list.length
  console.log('回退', len)
  if (len == 0) return
  const obj = list[len - 2]
  console.log(obj)
  if (obj) {
    const newObj = copyObject(obj)
    Object.keys(newObj).forEach(key => {
      // @ts-ignore
      pageOpts[key] = copyObject(obj[key])
    })
  }
  if (len > 1) {
    list.splice(len - 1, 1)
  }
}

// 复制设备
const copyDevice = (index: number) => {
  const item = copyObject(pageOpts.list[index])
  // if (item.type !== DEVICE_TYPE.DOT) {
  item.name = getDeviceName(item)
  item.deviceCode = getDeviceCode(item)
  // }

  item.style.x += pageOpts.copyGap || 100
  pageOpts.index = pageOpts.list.length
  pageOpts.list.push(item)
  addRecord()
}

const onKeyUp = (e: KeyboardEvent) => {
  const keyCode = e.keyCode

  // 回退
  if (e.ctrlKey && keyCode == 90) {
    backOperate()
    return
  }

  const index = pageOpts.index

  if (index < 0) return
  // 删除
  if (keyCode == 46) {
    pageOpts.list.splice(index, 1)
    pageOpts.index = -1
    return
  }

  if (!e.ctrlKey) return
  // 复制
  if (keyCode == 86) {
    copyDevice(index)
  }
}

// 键盘移动选中物体
const onKeydown = (e: KeyboardEvent) => {
  const keyCode = e.keyCode
  const index = pageOpts.index
  if (index < 0) return
  const et = { x: 0, y: 0 }
  // 上、下、左、右
  switch (keyCode) {
    case 38:
    case 87:
      et.y -= 1
      break
    case 40:
    case 83:
      et.y += 1
      break
    case 37:
    case 65:
      et.x -= 1
      break
    case 39:
    case 68:
      et.x += 1
      break
  }
  if (et.x == 0 && et.y == 0) return
  moveDrag(et)
}

const moveDrag = (e: { x: number; y: number }) => {
  const dot = pageOpts.list[pageOpts.index]
  if (e.x != 0) {
    dot.style.x += e.x
  }
  if (e.y != 0) {
    dot.style.y += e.y
  }
  addRecord()
}

addRecord()
window.addEventListener('keydown', onKeydown, false)
window.addEventListener('keyup', onKeyUp, false)

import DATA from './json/4-4-4-9'
onMounted(() => {
  const json = JSON.stringify(DATA)
  pageOpts.json = json
  formatJosn(json)
})

onBeforeUnmount(() => {
  window.removeEventListener('keydown', onKeydown)
  window.removeEventListener('keyup', onKeyUp)
})
</script>

<style lang="scss" module>
@use './style.scss';
</style>
